﻿using System.Linq;
using Domain;
using Domain.Services;

namespace Observers
{
    public class HighErrorCountObserver : Observer
    {
        private readonly int minOrdersWithErrors;
        private readonly int ordersQueried;

        public HighErrorCountObserver(int minOrdersWithErrors, int ordersQueried)
        {
            this.minOrdersWithErrors = minOrdersWithErrors;
            this.ordersQueried = ordersQueried;
        }

        public override void Update()
        {
            var recentOrders = Subject.RecentOrders(ordersQueried);

            if (recentOrders.Where(o => o.HasErrors).Count() > minOrdersWithErrors)
            {
                var alert = new Alert("{0} orders of the last {1} had errors.", minOrdersWithErrors,
                                      ordersQueried);
                alert.Send();
            }
        }
    }

    public class OrderErrorObserver : Observer
    {
        public override void Update()
        {
            if (Subject.LastOrder.HasErrors)
            {
                var alert = new Alert("Order #{0} has errors.", Subject.LastOrder.OrderNumber);
                alert.Send();
            }
        }
    }

    public class LargeOrderObserver : Observer
    {
        private readonly decimal maxAmount;

        public LargeOrderObserver(decimal maxAmount)
        {
            this.maxAmount = maxAmount;
        }

        public override void Update()
        {
            if (Subject.LastOrder.OrderAmount > maxAmount)
            {
                var alert =
                    new Alert(string.Format("Order #{0} was in the amount of {1:C2}", Subject.LastOrder.OrderNumber,
                                            Subject.LastOrder.OrderAmount));
                alert.Send();
            }
        }
    }

    public class OneTimeUseObserver : Observer
    {
        public override void Update()
        {
            if(Subject.LastOrder.Customer == "Dumpster Doggy")
            {
                var alert =
                    new Alert("Dumpster Doggy placed an order... that is all.");
                
                alert.Send();
                Subject.Detach(this);
            }
        }
    }

    public abstract class Observer : IObserver
    {
        /// <summary>
        /// Updates this instance.
        /// </summary>
        /// <remarks>
        /// This is what is called when the Subject notifies each of its observers that its state has changed.
        /// </remarks>
        public abstract void Update();

        /// <summary>
        /// Gets or sets the subject.
        /// </summary>
        /// <remarks>
        /// The OrderService is the 'Subject', basically what the Observer is observing.
        /// </remarks>
        /// <value>The subject.</value>
        public OrderService Subject { get; set; }
    }

    public interface IObserver
    {
        OrderService Subject { get; set; }

        void Update();
    }
}